<!DOCTYPE html>
<html lang="en" dir="ltr">

<head>
  <meta name="generator" content="Hugo 0.82.1" />
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="[golang] 并发处理 - Go 协程#概念# go 协程(goroutines)  由于 threads, coroutines 和 processes 不能精确的表达 Go 语言的设计想法。Go 语言使用一个新的词汇： goroutines。
goroutine 的模型: 在同一个地址空间里，一个 goroutine 是一个(可以和多个 goroutines) 并发执行的函数。它是轻量级的，比栈空间的分配的成本稍微高一点。可根据需要使用堆空间。
发起一个 goroutine 很很简单， 使用 go 语句即可:
go list.Sort() // run list.Sort concurrently; don&#39;t wait for it.  channels  Go 语言中，并发处理的口号:
 Do not communicate by sharing memory; instead, share memory by communicating.
 在 Go 语言中，为了避免 data race 问题，Go 不会在多个 goroutines 之间共享内存。而是通过 channel来交流数据 。">
<meta name="theme-color" content="#FFFFFF"><meta property="og:title" content="并发处理 - Go 协程" />
<meta property="og:description" content="[golang] 并发处理 - Go 协程#概念# go 协程(goroutines)  由于 threads, coroutines 和 processes 不能精确的表达 Go 语言的设计想法。Go 语言使用一个新的词汇： goroutines。
goroutine 的模型: 在同一个地址空间里，一个 goroutine 是一个(可以和多个 goroutines) 并发执行的函数。它是轻量级的，比栈空间的分配的成本稍微高一点。可根据需要使用堆空间。
发起一个 goroutine 很很简单， 使用 go 语句即可:
go list.Sort() // run list.Sort concurrently; don&#39;t wait for it.  channels  Go 语言中，并发处理的口号:
 Do not communicate by sharing memory; instead, share memory by communicating.
 在 Go 语言中，为了避免 data race 问题，Go 不会在多个 goroutines 之间共享内存。而是通过 channel来交流数据 。" />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://example.org/docs/go-routine/" /><meta property="article:section" content="docs" />



<title>并发处理 - Go 协程 | My Golang Book</title>
<link rel="manifest" href="/manifest.json">
<link rel="icon" href="/favicon.png" type="image/x-icon">
<link rel="stylesheet" href="/book.min.2bc2364a4a4b31f0ec1debecf0a8f90a840821f143dfe1ac6a0f7cbcbdcf64ac.css" integrity="sha256-K8I2SkpLMfDsHevs8Kj5CoQIIfFD3&#43;Gsag98vL3PZKw=">
<script defer src="/en.search.min.84ce9693e6c02d95376f29aeb794c11824d09ed0440f910f008e91e9ed0436e4.js" integrity="sha256-hM6Wk&#43;bALZU3bymut5TBGCTQntBED5EPAI6R6e0ENuQ="></script>
<!--
Made with Book Theme
https://github.com/alex-shpak/hugo-book
-->

  
</head>

<body dir="ltr">
  <input type="checkbox" class="hidden toggle" id="menu-control" />
  <input type="checkbox" class="hidden toggle" id="toc-control" />
  <main class="container flex">
    <aside class="book-menu">
      <div class="book-menu-content">
        
  <nav>
<h2 class="book-brand">
  <a href="/"><span>My Golang Book</span>
  </a>
</h2>


<div class="book-search">
  <input type="text" id="book-search-input" placeholder="Search" aria-label="Search" maxlength="64" data-hotkeys="s/" />
  <div class="book-search-spinner hidden"></div>
  <ul id="book-search-results"></ul>
</div>











  



  
  <ul>
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/introduction/" class="">Golang 介绍</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/installation/" class="">安装、准备开发环境</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/go-routine/" class=" active">并发处理 - Go 协程</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/workspace-module/" class="">管理Go模块</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/erro-handling/" class="">错误处理</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/resources/" class="">Golang 资源</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/statements/" class="">Go For语句</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/guidelines/" class="">Go 开发规范</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/logging/" class="">日志</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/data-init/" class="">Data Init</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/data-types/" class="">Data Types</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/debug/" class="">Debug</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/dynamic-programing/" class="">Dynamic Programing</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/ecosystem/" class="">Ecosystem</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/performance/" class="">Performance</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/struct-interface/" class="">Struct Interface</a>
  

        </li>
      
    
      
        <li>
          
  
  

  
    <a href="http://example.org/docs/struct-tags/" class="">Struct Tags</a>
  

        </li>
      
    
  </ul>















</nav>




  <script>(function(){var a=document.querySelector("aside.book-menu nav");addEventListener("beforeunload",function(b){localStorage.setItem("menu.scrollTop",a.scrollTop)}),a.scrollTop=localStorage.getItem("menu.scrollTop")})()</script>


 
      </div>
    </aside>

    <div class="book-page">
      <header class="book-header">
        
  <div class="flex align-center justify-between">
  <label for="menu-control">
    <img src="/svg/menu.svg" class="book-icon" alt="Menu" />
  </label>

  <strong>并发处理 - Go 协程</strong>

  <label for="toc-control">
    
    <img src="/svg/toc.svg" class="book-icon" alt="Table of Contents" />
    
  </label>
</div>


  
  <aside class="hidden clearfix">
    
  
<nav id="TableOfContents">
  <ul>
    <li><a href="#概念">概念</a></li>
    <li><a href="#案例-实现锁">案例: 实现锁</a></li>
    <li><a href="#案例-实现信号标semaphore">案例: 实现信号标(semaphore)</a></li>
    <li><a href="#案例-并行化">案例: 并行化</a></li>
    <li><a href="#案例-漏桶leaky-bucket">案例: 漏桶(leaky bucket)</a></li>
    <li><a href="#总结">总结</a></li>
    <li><a href="#参照">参照</a></li>
  </ul>
</nav>



  </aside>
  
 
      </header>

      
      
  <article class="markdown"><h1 id="golang-并发处理---go-协程">
  [golang] 并发处理 - Go 协程
  <a class="anchor" href="#golang-%e5%b9%b6%e5%8f%91%e5%a4%84%e7%90%86---go-%e5%8d%8f%e7%a8%8b">#</a>
</h1>
<h2 id="概念">
  概念
  <a class="anchor" href="#%e6%a6%82%e5%bf%b5">#</a>
</h2>
<ul>
<li>go 协程(goroutines)</li>
</ul>
<p>由于 threads, coroutines 和 processes 不能精确的表达 Go 语言的设计想法。Go 语言使用一个新的词汇： <code>goroutines</code>。</p>
<p><code>goroutine</code> 的模型: 在同一个地址空间里，一个 <code>goroutine</code> 是一个(可以和多个 <code>goroutines</code>) 并发执行的函数。它是轻量级的，比栈空间的分配的成本稍微高一点。可根据需要使用堆空间。</p>
<p>发起一个 <code>goroutine</code> 很很简单， 使用 <code>go</code> 语句即可:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">list</span>.<span style="color:#a6e22e">Sort</span>()  <span style="color:#75715e">// run list.Sort concurrently; don&#39;t wait for it.
</span></code></pre></div><ul>
<li>channels</li>
</ul>
<p>Go 语言中，并发处理的口号:</p>
<blockquote>
<p>Do not communicate by sharing memory; instead, share memory by communicating.</p>
</blockquote>
<p>在 Go 语言中，为了避免 <code>data race</code> 问题，Go 不会在多个 <code>goroutines</code> 之间共享内存。而是通过 <code>channel</code>来交流数据 。</p>
<p><code>chan &lt;- value</code> : 向一个 channel 发送一个值</p>
<p><code>&lt;- chan</code> : 等待一个 channel 的值。可以起到 wait 的作用。</p>
<h2 id="案例-实现锁">
  案例: 实现锁
  <a class="anchor" href="#%e6%a1%88%e4%be%8b-%e5%ae%9e%e7%8e%b0%e9%94%81">#</a>
</h2>
<p>通道(channel)有两种：无缓存通道，和有缓存通道。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// 创建无缓存通道。
</span><span style="color:#75715e"></span><span style="color:#a6e22e">ci</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>)            <span style="color:#75715e">// unbuffered channel of integers
</span><span style="color:#75715e"></span><span style="color:#a6e22e">cj</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>, <span style="color:#ae81ff">0</span>)         <span style="color:#75715e">// unbuffered channel of integers
</span><span style="color:#75715e"></span>
<span style="color:#75715e">// 创建有缓存通道
</span><span style="color:#75715e"></span><span style="color:#a6e22e">cs</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">File</span>, <span style="color:#ae81ff">100</span>)  <span style="color:#75715e">// buffered channel of pointers to Files
</span></code></pre></div><p>无缓存通道的特点:</p>
<ul>
<li>接受者在接受到信号前，会被被阻塞。</li>
<li>发送者会在接受者接受到信号后才会继续执行。</li>
</ul>
<p>我们可以利用这个特点来实现锁。</p>
<p>示例：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>)  <span style="color:#75715e">// Allocate a channel.
</span><span style="color:#75715e">// Start the sort in a goroutine; when it completes, signal on the channel.
</span><span style="color:#75715e"></span><span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
    <span style="color:#a6e22e">list</span>.<span style="color:#a6e22e">Sort</span>()
    <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">1</span>  <span style="color:#75715e">// Send a signal; value does not matter.
</span><span style="color:#75715e"></span>}()
<span style="color:#a6e22e">doSomethingForAWhile</span>()
<span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">c</span>   <span style="color:#75715e">// Wait for sort to finish; discard sent value.
</span></code></pre></div><h2 id="案例-实现信号标semaphore">
  案例: 实现信号标(semaphore)
  <a class="anchor" href="#%e6%a1%88%e4%be%8b-%e5%ae%9e%e7%8e%b0%e4%bf%a1%e5%8f%b7%e6%a0%87semaphore">#</a>
</h2>
<p>有缓存通道的特点:</p>
<ul>
<li>接受者在接受到信号前，会被被阻塞。</li>
<li>发送者在信号被拷贝到缓存后，就会继续执行。</li>
<li>当缓存满了的场合，发送者必须等到一个接受者接收到信号后，缓存有了空间，发送者的信号被复制之后，才会继续执行。</li>
</ul>
<p>我们可以利用这个特点来实现信号标(semaphore)。限制同时可以运行 Go 协程最大数。</p>
<p>示例：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">sem</span> = make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">semaphoreSize</span>)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">Serve</span>(<span style="color:#a6e22e">queue</span> <span style="color:#66d9ef">chan</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Request</span>) {
    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">req</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">queue</span> {
        <span style="color:#a6e22e">req</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">req</span> <span style="color:#75715e">// 创建一个新的reg实例，并保持同样的变量名
</span><span style="color:#75715e"></span>        <span style="color:#a6e22e">sem</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">1</span>
        <span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
            <span style="color:#a6e22e">process</span>(<span style="color:#a6e22e">req</span>)
            <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">sem</span>
        }()
    }
}
</code></pre></div><p>由于 Go 语言中，<code>for</code> 中的 循环变量 <code>req</code> 会被复用于每一次循环中。因此，变量 <code>reg</code> 被所有的 Go 协程共享。这个破坏了 Go 的口号。
所以 Go 有一个惯用语句 <code>req := req</code> ，这条语句是一个 <code>shadow</code> 语句，会创建一个新的实例，而变量名没有变化。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// 创建一个新的reg实例，并保持同样的变量名。
</span><span style="color:#75715e"></span><span style="color:#a6e22e">req</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">req</span>
</code></pre></div><h2 id="案例-并行化">
  案例: 并行化
  <a class="anchor" href="#%e6%a1%88%e4%be%8b-%e5%b9%b6%e8%a1%8c%e5%8c%96">#</a>
</h2>
<p>对于需要大量计算的函数，如果可以拆分为可以独立计算的子函数。我们会期望根据计算机的内核数做并行化的处理。</p>
<ul>
<li>获取 CPU 内核数的方法</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">numCPU</span> = <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">NumCPU</span>()
</code></pre></div><ul>
<li>获取用户指定可以并行运行内核数。
默认值是: <code>runtime.NumCPU()</code></li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">numCPU</span> = <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">GOMAXPROCS</span>(<span style="color:#ae81ff">0</span>)
</code></pre></div><p>示例:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Vector</span> []<span style="color:#66d9ef">float64</span>

<span style="color:#75715e">// Apply the operation to v[i], v[i+1] ... up to v[n-1].
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vector</span>) <span style="color:#a6e22e">DoSome</span>(<span style="color:#a6e22e">i</span>, <span style="color:#a6e22e">n</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">u</span> <span style="color:#a6e22e">Vector</span>, <span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>) {
    <span style="color:#66d9ef">for</span> ; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">n</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
        <span style="color:#a6e22e">v</span>[<span style="color:#a6e22e">i</span>] <span style="color:#f92672">+=</span> <span style="color:#a6e22e">u</span>.<span style="color:#a6e22e">Op</span>(<span style="color:#a6e22e">v</span>[<span style="color:#a6e22e">i</span>])
    }
    <span style="color:#a6e22e">c</span> <span style="color:#f92672">&lt;-</span> <span style="color:#ae81ff">1</span>    <span style="color:#75715e">// signal that this piece is done
</span><span style="color:#75715e"></span>}

<span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">v</span> <span style="color:#a6e22e">Vector</span>) <span style="color:#a6e22e">DoAll</span>(<span style="color:#a6e22e">u</span> <span style="color:#a6e22e">Vector</span>) {
    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">numCPU</span> = <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">GOMAXPROCS</span>(<span style="color:#ae81ff">0</span>)

    <span style="color:#a6e22e">c</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#66d9ef">int</span>, <span style="color:#a6e22e">numCPU</span>)  <span style="color:#75715e">// Buffering optional but sensible.
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">numCPU</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
        <span style="color:#66d9ef">go</span> <span style="color:#a6e22e">v</span>.<span style="color:#a6e22e">DoSome</span>(<span style="color:#a6e22e">i</span><span style="color:#f92672">*</span>len(<span style="color:#a6e22e">v</span>)<span style="color:#f92672">/</span><span style="color:#a6e22e">numCPU</span>, (<span style="color:#a6e22e">i</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)<span style="color:#f92672">*</span>len(<span style="color:#a6e22e">v</span>)<span style="color:#f92672">/</span><span style="color:#a6e22e">numCPU</span>, <span style="color:#a6e22e">u</span>, <span style="color:#a6e22e">c</span>)
    }
    <span style="color:#75715e">// Drain the channel.
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; <span style="color:#a6e22e">numCPU</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> {
        <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">c</span>    <span style="color:#75715e">// wait for one task to complete
</span><span style="color:#75715e"></span>    }
    <span style="color:#75715e">// All done.
</span><span style="color:#75715e"></span>}
</code></pre></div><h2 id="案例-漏桶leaky-bucket">
  案例: 漏桶(leaky bucket)
  <a class="anchor" href="#%e6%a1%88%e4%be%8b-%e6%bc%8f%e6%a1%b6leaky-bucket">#</a>
</h2>
<p>这是一个官方的例子，说明将通道(channel)用于非并发的例子。
漏桶的背景说明：</p>
<ul>
<li>有两组协程
一组被称为客户协程，使用函数 client();
一组被称为服务协程，使用函数 server();
client() 和 server() 的交互是通过 <code>chan *Buffer</code>。
为了减少对 Buffer 分配和释放操作引起的消耗。漏桶提供了一种模式，</li>
</ul>
<p>业务如下：</p>
<ul>
<li>
<p>客户端从一个数据源（比如：网络）获取数据；</p>
</li>
<li>
<p>客户端为了避免分配和释放缓存，使用了一个 freeList ，这个 freeList 是一个有缓存的通道(channel)；</p>
</li>
<li>
<p>如果通道 freeList 是空的，分配一个新的 buffer；</p>
</li>
<li>
<p>一旦这个消息 buffer 准备好了，通过通道 serverChan 发送到服务端；</p>
</li>
<li>
<p>服务端在一个循环里，收到一个消息，处理它，然后通过通道 freeList 返回给客户端；</p>
</li>
<li>
<p>客户端尝试从 freeList 中获取一个 buffer；如果 什么都没有，就分配一个新的 buffer 空间。</p>
<p>The client attempts to retrieve a buffer from freeList; if none is available, it allocates a fresh one. The server&rsquo;s send to freeList puts b back on the free list unless the list is full, in which case the buffer is dropped on the floor to be reclaimed by the garbage collector. (The default clauses in the select statements execute when no other case is ready, meaning that the selects never block.) This implementation builds a leaky bucket free list in just a few lines, relying on the buffered channel and the garbage collector for bookkeeping.</p>
</li>
</ul>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">freeList</span> = make(<span style="color:#66d9ef">chan</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Buffer</span>, <span style="color:#ae81ff">100</span>)
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">serverChan</span> = make(<span style="color:#66d9ef">chan</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Buffer</span>)

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">client</span>() {
    <span style="color:#66d9ef">for</span> {
        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">b</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Buffer</span>
        <span style="color:#75715e">// Grab a buffer if available; allocate if not.
</span><span style="color:#75715e"></span>        <span style="color:#66d9ef">select</span> {
        <span style="color:#66d9ef">case</span> <span style="color:#a6e22e">b</span> = <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">freeList</span>:
            <span style="color:#75715e">// Got one; nothing more to do.
</span><span style="color:#75715e"></span>        <span style="color:#66d9ef">default</span>:
            <span style="color:#75715e">// None free, so allocate a new one.
</span><span style="color:#75715e"></span>            <span style="color:#a6e22e">b</span> = new(<span style="color:#a6e22e">Buffer</span>)
        }
        <span style="color:#a6e22e">load</span>(<span style="color:#a6e22e">b</span>)              <span style="color:#75715e">// Read next message from the net.
</span><span style="color:#75715e"></span>        <span style="color:#a6e22e">serverChan</span> <span style="color:#f92672">&lt;-</span> <span style="color:#a6e22e">b</span>      <span style="color:#75715e">// Send to server.
</span><span style="color:#75715e"></span>    }
}
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">server</span>() {
    <span style="color:#66d9ef">for</span> {
        <span style="color:#a6e22e">b</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">serverChan</span>    <span style="color:#75715e">// Wait for work.
</span><span style="color:#75715e"></span>        <span style="color:#a6e22e">process</span>(<span style="color:#a6e22e">b</span>)
        <span style="color:#75715e">// Reuse buffer if there&#39;s room.
</span><span style="color:#75715e"></span>        <span style="color:#66d9ef">select</span> {
        <span style="color:#66d9ef">case</span> <span style="color:#a6e22e">freeList</span> <span style="color:#f92672">&lt;-</span> <span style="color:#a6e22e">b</span>:
            <span style="color:#75715e">// Buffer on free list; nothing more to do.
</span><span style="color:#75715e"></span>        <span style="color:#66d9ef">default</span>:
            <span style="color:#75715e">// Free list full, just carry on.
</span><span style="color:#75715e"></span>        }
    }
}
</code></pre></div><h2 id="总结">
  总结
  <a class="anchor" href="#%e6%80%bb%e7%bb%93">#</a>
</h2>
<p>无缓存通道的特点:</p>
<ul>
<li>接受者在接受到信号前，会被被阻塞。</li>
<li>发送者会在接受者接受到信号后才会继续执行。</li>
</ul>
<p>有缓存通道的特点:</p>
<ul>
<li>接受者在接受到信号前，会被被阻塞。</li>
<li>发送者在信号被拷贝到缓存后，就会继续执行。</li>
<li>当缓存满了的场合，发送者必须等到一个接受者接收到信号后，缓存有了空间，发送者的信号被复制之后，才会继续执行。</li>
</ul>
<h2 id="参照">
  参照
  <a class="anchor" href="#%e5%8f%82%e7%85%a7">#</a>
</h2>
<ul>
<li><a href="https://golang.org/doc/effective_go#concurrency">Effective GO concurrency</a></li>
</ul>
</article>
 
      

      <footer class="book-footer">
        
  <div class="flex flex-wrap justify-between">





</div>

 
        
      </footer>

      
  
  <div class="book-comments">

</div>
  
 

      <label for="menu-control" class="hidden book-menu-overlay"></label>
    </div>

    
    <aside class="book-toc">
      <div class="book-toc-content">
        
  
<nav id="TableOfContents">
  <ul>
    <li><a href="#概念">概念</a></li>
    <li><a href="#案例-实现锁">案例: 实现锁</a></li>
    <li><a href="#案例-实现信号标semaphore">案例: 实现信号标(semaphore)</a></li>
    <li><a href="#案例-并行化">案例: 并行化</a></li>
    <li><a href="#案例-漏桶leaky-bucket">案例: 漏桶(leaky bucket)</a></li>
    <li><a href="#总结">总结</a></li>
    <li><a href="#参照">参照</a></li>
  </ul>
</nav>


 
      </div>
    </aside>
    
  </main>

  
</body>

</html>












